﻿///////////////////////////////////////////////////////////////////////////////
// File Name: EditSkin.cpp 
// Purpose: EditSkin.h 实现文件
// Author: 张东斌、ChongyangLee
// E_Mail: malutianshi7905@sina.com; ChongyangLee@hotmail.com
// History: 
// 2009/10/05 DEL 删除两个不需要的函数
// 
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SkinTools.h"
#include "detours.h"
#include "InitSkinTK.h"


static TCHAR szPropStr[] = _T("SkinScrollBarPtr");


SCROLLWND *GetScrollWndFromHwnd(HWND hwnd)
{
	return (SCROLLWND *)GetProp(hwnd, szPropStr);
}
static void RedrawNonClient(HWND hwnd, BOOL fFrameChanged)
{
	if(fFrameChanged == FALSE)
	{
		SendMessage(hwnd, WM_NCPAINT, (WPARAM)NULL, 0);
	}
	else
	{
		SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE
			| SWP_FRAMECHANGED | SWP_DRAWFRAME);
	}
}
SCROLLBAR *GetScrollBarFromHwnd(HWND hwnd, UINT nBar)
{
	SCROLLWND *sw = GetScrollWndFromHwnd(hwnd);

	if(!sw) return 0;

	if(nBar == SB_HORZ)
		return &sw->sbarHorz;
	else if(nBar == SB_VERT)
		return &sw->sbarVert;
	else
		return 0;
}
BOOL WINAPI Skin_IsThumbTracking(HWND hwnd)	
{ 
	SCROLLWND *sw;

	if((sw = GetScrollWndFromHwnd(hwnd)) == NULL)
		return FALSE;
	else
		return sw->fThumbTracking; 
}
BOOL WINAPI Skin_IsCoolScrollEnabled(HWND hwnd)
{
	if(GetScrollWndFromHwnd(hwnd))
		return TRUE;
	else
		return FALSE;
}

SCROLLINFO *GetScrollInfoFromHwnd(HWND hwnd, int fnBar)
{
	SCROLLBAR *sb = GetScrollBarFromHwnd(hwnd, fnBar);

	if(sb == 0)
		return FALSE;

	if(fnBar == SB_HORZ)
	{
		return &sb->scrollInfo;
	}
	else if(fnBar == SB_VERT)
	{
		return &sb->scrollInfo;
	}
	else
		return NULL;
}

BOOL WINAPI Skin_EnableScrollBar(HWND hwnd, int wSBflags, UINT wArrows)
{
	SCROLLBAR *sbar;
	UINT oldstate;
	BOOL bFailed = FALSE;

	if(!Skin_IsCoolScrollEnabled(hwnd))
		return EnableScrollBar(hwnd, wSBflags, wArrows);

	if((wSBflags == SB_HORZ || wSBflags == SB_BOTH) && 
		(sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		oldstate = sbar->fScrollFlags;
		sbar->fScrollFlags = (sbar->fScrollFlags & ~ESB_DISABLE_BOTH) | wArrows;

		if(oldstate == sbar->fScrollFlags)
			bFailed = TRUE;

	}

	if((wSBflags == SB_VERT || wSBflags == SB_BOTH) && 
		(sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		oldstate = sbar->fScrollFlags;
		sbar->fScrollFlags = (sbar->fScrollFlags & ~ESB_DISABLE_BOTH) | wArrows;

		if(oldstate == sbar->fScrollFlags)
			bFailed = TRUE;
	}

	return !bFailed;
}

BOOL WINAPI Skin_GetScrollBarInfo(HWND hwnd)
{
	return FALSE;	
}

BOOL WINAPI Skin_GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
	SCROLLINFO *mysi;
	BOOL copied = FALSE;

	if(!lpsi)
		return FALSE;

	if(!(mysi = GetScrollInfoFromHwnd(hwnd, fnBar)))
	{
		return GetScrollInfo(hwnd, fnBar, lpsi);
	}

	if(lpsi->fMask & SIF_PAGE)
	{
		lpsi->nPage = mysi->nPage;
		copied = TRUE;
	}

	if(lpsi->fMask & SIF_POS)
	{
		lpsi->nPos = mysi->nPos;
		copied = TRUE;
	}

	if(lpsi->fMask & SIF_TRACKPOS)
	{
		lpsi->nTrackPos = mysi->nTrackPos;
		copied = TRUE;
	}

	if(lpsi->fMask & SIF_RANGE)
	{
		lpsi->nMin = mysi->nMin;
		lpsi->nMax = mysi->nMax;
		copied = TRUE;
	}

	return copied;
}

int	WINAPI Skin_GetScrollPos (HWND hwnd, int nBar)
{
	SCROLLINFO *mysi;

	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
		return GetScrollPos(hwnd, nBar);

	return mysi->nPos;
}

BOOL WINAPI Skin_GetScrollRange (HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
{
	SCROLLINFO *mysi;

	if(!lpMinPos || !lpMaxPos)
		return FALSE;

	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
		return GetScrollRange(hwnd, nBar, lpMinPos, lpMaxPos);

	*lpMinPos = mysi->nMin;
	*lpMaxPos = mysi->nMax;

	return TRUE;
}

int	WINAPI Skin_SetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw)
{
	SCROLLINFO *mysi;
	SCROLLBAR *sbar;
	BOOL       fRecalcFrame = FALSE;

	if(!lpsi)
		return FALSE;

	if(!(mysi = GetScrollInfoFromHwnd(hwnd, fnBar)))
		return SetScrollInfo(hwnd, fnBar, lpsi, fRedraw);

	if(lpsi->fMask & SIF_RANGE)
	{
		mysi->nMin = lpsi->nMin;
		mysi->nMax = lpsi->nMax;
	}

	//The nPage member must specify a value from 0 to nMax - nMin +1. 
	if(lpsi->fMask & SIF_PAGE)
	{
		UINT t = (UINT)(mysi->nMax - mysi->nMin + 1);
		mysi->nPage = min(max(0, lpsi->nPage), t);
	}

	//The nPos member must specify a value between nMin and nMax - max(nPage - 1, 0).
	if(lpsi->fMask & SIF_POS)
	{
		mysi->nPos = max(lpsi->nPos, mysi->nMin);
		mysi->nPos = min((UINT)mysi->nPos, mysi->nMax - max(mysi->nPage - 1, 0));
	}

	sbar = GetScrollBarFromHwnd(hwnd, fnBar);

	if((lpsi->fMask & SIF_DISABLENOSCROLL)  || (sbar->fScrollFlags & 4))
	{
		if(!sbar->fScrollVisible)
		{
			Skin_ShowScrollBar(hwnd, fnBar, TRUE);
			fRecalcFrame = TRUE;
		}
	}
	else
	{
		if(    mysi->nPage >  (UINT)mysi->nMax 
			|| mysi->nPage == (UINT)mysi->nMax &&mysi->nMax == 0
			|| mysi->nMax  <= mysi->nMin)
		{
			if(sbar->fScrollVisible)
			{
				Skin_ShowScrollBar(hwnd, fnBar, FALSE);
				fRecalcFrame = TRUE;
			}
		}
		else
		{
			if(!sbar->fScrollVisible)
			{
				Skin_ShowScrollBar(hwnd, fnBar, TRUE);
				fRecalcFrame = TRUE;
			}

		}
	}

	if(fRedraw && !Skin_IsThumbTracking(hwnd))
		RedrawNonClient(hwnd, fRecalcFrame);

	return mysi->nPos;
}


int WINAPI Skin_SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL fRedraw)
{
	SCROLLINFO *mysi;
	int oldpos;

	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
	{
		return SetScrollPos(hwnd, nBar, nPos, fRedraw);
	}

	oldpos = mysi->nPos;
	mysi->nPos = max(nPos, mysi->nMin);
	mysi->nPos = min((UINT)mysi->nPos, mysi->nMax - max(mysi->nPage - 1, 0));

	if(fRedraw && !Skin_IsThumbTracking(hwnd))
		RedrawNonClient(hwnd, FALSE);

	return oldpos;
}

int WINAPI Skin_SetScrollRange (HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw)
{
	SCROLLINFO *mysi;
	SCROLLBAR *sbar;
	BOOL       fRecalcFrame = FALSE;

	if(!(mysi = GetScrollInfoFromHwnd(hwnd, nBar)))
		return SetScrollRange(hwnd, nBar, nMinPos, nMaxPos, fRedraw);

	if(Skin_IsThumbTracking(hwnd))
		return mysi->nPos;

	mysi->nMin = nMinPos;
	mysi->nMax = nMaxPos;

	sbar = GetScrollBarFromHwnd(hwnd, nBar);
	if(  mysi->nMax  <= mysi->nMin)
	{
		if(sbar->fScrollVisible)
		{
			Skin_ShowScrollBar(hwnd, nBar, FALSE);
			fRecalcFrame = TRUE;
		}
	}
	else
	{
		if(!sbar->fScrollVisible)
		{
			Skin_ShowScrollBar(hwnd, nBar, TRUE);
			fRecalcFrame = TRUE;
		}

	}
	
	if(fRedraw)
		RedrawNonClient(hwnd, fRecalcFrame);

	return TRUE;
}

BOOL WINAPI Skin_ShowScrollBar (HWND hwnd, int wBar, BOOL fShow)
{
	SCROLLBAR *sbar;
	BOOL bFailed = FALSE;
#ifdef _WIN64
	LONG_PTR dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
#else
	DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
#endif
	if(!Skin_IsCoolScrollEnabled(hwnd))
		return ShowScrollBar(hwnd, wBar, fShow);

	if((wBar == SB_HORZ || wBar == SB_BOTH) && 
		(sbar = GetScrollBarFromHwnd(hwnd, SB_HORZ)))
	{
		bFailed = TRUE;
		sbar->fScrollFlags  =  sbar->fScrollFlags & ~CSBS_VISIBLE;
		sbar->fScrollFlags |= (fShow == TRUE ? CSBS_VISIBLE : 0);

		LONG istyle = fShow ? (dwStyle | WS_HSCROLL) : (dwStyle & WS_HSCROLL);
	#ifdef _WIN64
		SetWindowLongPtr(hwnd, GWL_STYLE, istyle);
	#else
		SetWindowLong(hwnd, GWL_STYLE, istyle);
	#endif
	}

	if((wBar == SB_VERT || wBar == SB_BOTH) && 
		(sbar = GetScrollBarFromHwnd(hwnd, SB_VERT)))
	{
		bFailed = TRUE;
		sbar->fScrollFlags  =  sbar->fScrollFlags & ~CSBS_VISIBLE;
		sbar->fScrollFlags |= (fShow == TRUE ? CSBS_VISIBLE : 0);

		LONG istyle = fShow ? (dwStyle | WS_VSCROLL) : (dwStyle & WS_VSCROLL);
	#ifdef _WIN64
		SetWindowLongPtr(hwnd, GWL_STYLE, istyle);
	#else
		SetWindowLong(hwnd, GWL_STYLE, istyle);
	#endif
	}

	if(bFailed)
	{
		return FALSE;
	}
	else
	{
		SetWindowPos(hwnd, 0, 0, 0, 0, 0, 
			SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | 
			SWP_NOACTIVATE | SWP_FRAMECHANGED);

		return TRUE;
	}
}



static BOOL (WINAPI *Detour_EnableScrollBar	)(HWND hwnd, UINT wSBflags, UINT wArrows) = EnableScrollBar;
static BOOL (WINAPI *Detour_GetScrollInfo	)(HWND hwnd, int fnBar, LPSCROLLINFO lpsi) =  GetScrollInfo;
static int  (WINAPI *Detour_GetScrollPos	)(HWND hwnd, int nBar) = GetScrollPos;
static BOOL (WINAPI *Detour_GetScrollRange	)(HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos) = GetScrollRange;
static int  (WINAPI *Detour_SetScrollInfo	)(HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, BOOL fRedraw) = SetScrollInfo;
static int  (WINAPI *Detour_SetScrollPos	)(HWND hwnd, int nBar, int nPos, BOOL fRedraw) =  SetScrollPos;
static int  (WINAPI *Detour_SetScrollRange	)(HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw) = SetScrollRange;
static BOOL (WINAPI *Detour_ShowScrollBar	)(HWND hwnd, int wBar, BOOL fShow) = ShowScrollBar;

static BOOL WINAPI Tramp_EnableScrollBar(HWND hwnd, int wSBflags, UINT wArrows)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_EnableScrollBar(hwnd, wSBflags, wArrows);
	else
		return Detour_EnableScrollBar(hwnd, wSBflags, wArrows);
}

static BOOL WINAPI Tramp_GetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_GetScrollInfo(hwnd, fnBar, lpsi);
	else
		return Detour_GetScrollInfo(hwnd, fnBar, lpsi);
}

static int	 WINAPI Tramp_GetScrollPos(HWND hwnd, int nBar)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_GetScrollPos(hwnd, nBar);
	else
		return Detour_GetScrollPos(hwnd, nBar);
}

static BOOL WINAPI Tramp_GetScrollRange(HWND hwnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
{
	
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_GetScrollRange(hwnd, nBar, lpMinPos, lpMaxPos);
	else
		return Detour_GetScrollRange(hwnd, nBar, lpMinPos, lpMaxPos);
}

static int	 WINAPI Tramp_SetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_SetScrollInfo(hwnd, fnBar, lpsi, fRedraw);
	else
		return Detour_SetScrollInfo(hwnd, fnBar, lpsi, fRedraw);
	
}

static int  WINAPI Tramp_SetScrollPos(HWND hwnd, int nBar, int nPos, BOOL fRedraw)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_SetScrollPos(hwnd, nBar, nPos, fRedraw);
	else
		return Detour_SetScrollPos(hwnd, nBar, nPos, fRedraw);
	
}

static int  WINAPI Tramp_SetScrollRange(HWND hwnd, int nBar, int nMinPos, int nMaxPos, BOOL fRedraw)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_SetScrollRange(hwnd, nBar, nMinPos, nMaxPos, fRedraw);
	else
		return Detour_SetScrollRange(hwnd, nBar, nMinPos, nMaxPos, fRedraw);
}

static BOOL WINAPI Tramp_ShowScrollBar(HWND hwnd, int wBar, BOOL fShow)
{
	if(Skin_IsCoolScrollEnabled(hwnd))	
		return Skin_ShowScrollBar(hwnd, wBar, fShow);
	else
		return Detour_ShowScrollBar(hwnd, wBar, fShow);
}

BOOL WINAPI SB_InitializeApp(void)
{
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourAttach(&(PVOID&)Detour_EnableScrollBar, Tramp_EnableScrollBar);
	DetourAttach(&(PVOID&)Detour_GetScrollInfo, Tramp_GetScrollInfo);
	DetourAttach(&(PVOID&)Detour_GetScrollPos, Tramp_GetScrollPos);
	DetourAttach(&(PVOID&)Detour_GetScrollRange, Tramp_GetScrollRange);
	DetourAttach(&(PVOID&)Detour_SetScrollInfo, Tramp_SetScrollInfo);
	DetourAttach(&(PVOID&)Detour_SetScrollPos, Tramp_SetScrollPos);
	DetourAttach(&(PVOID&)Detour_SetScrollRange, Tramp_SetScrollRange);
	DetourAttach(&(PVOID&)Detour_ShowScrollBar, Tramp_ShowScrollBar);
	DetourTransactionCommit();

	return TRUE;
}

BOOL WINAPI SB_UninitializeApp(void)
{
	DetourTransactionBegin();
	DetourUpdateThread(GetCurrentThread());
	DetourDetach(&(PVOID&)Detour_EnableScrollBar, Tramp_EnableScrollBar);
	DetourDetach(&(PVOID&)Detour_GetScrollInfo, Tramp_GetScrollInfo);
	DetourDetach(&(PVOID&)Detour_GetScrollPos, Tramp_GetScrollPos);
	DetourDetach(&(PVOID&)Detour_GetScrollRange, Tramp_GetScrollRange);
	DetourDetach(&(PVOID&)Detour_SetScrollInfo, Tramp_SetScrollInfo);
	DetourDetach(&(PVOID&)Detour_SetScrollPos, Tramp_SetScrollPos);
	DetourDetach(&(PVOID&)Detour_SetScrollRange, Tramp_SetScrollRange);
	DetourDetach(&(PVOID&)Detour_ShowScrollBar, Tramp_ShowScrollBar);
	DetourTransactionCommit();
	return TRUE;
}